package com.atguigu.juc;

import lombok.Getter;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author: shenhao
 * @CreatTime: 2024/10/24 16:52
 * @Version: 1.0
 * 正确关闭线程池姿势-优雅停机
 */
public class ThreadPoolGracefulShutdownDemo {
    public static void main(String[] args) {
        //shutdown_Test();
        //shutdownNow_Test();
        //shutdown_awaitTermination_Test();
        //shutdownNow_awaitTermination_Test();
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        try{

        } catch (Exception e){
            e.printStackTrace();
        } finally {
            finalOK_shutdownAndAwaitTermination(threadPool);
        }
    }

    private static void shutdownNow_awaitTermination_Test() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //提交10个任务，在第5个任务提交完，准备提交第6个的时候执行shutdown
        for (int i = 1; i <= 10; i++) {
            System.out.println("第:" + i + " 次提交:threadPool.isShutdown: " + threadPool.isShutdown());
            //此处故意不加try...catch块，方便效果演示
            try {
                threadPool.execute(new Task(i));
            } catch (RejectedExecutionException e) {
                //e.printStackTrace();
                System.out.println("rejected,task-" + i);
            }
            //i等于5的时候shutdown，意味着从第6次开始就不能提交新任务
            if (i == 5) {
                List<Runnable> runnables = threadPool.shutdownNow();// 关闭后不是线程池立即停止,等待前面已经提交的任务结束,不在接收新的任务
                runnables.forEach((runnable) -> {
                    if (runnable instanceof Task) {
                        System.out.println("waiting task: " + ((Task) runnable).getName());
                    }
                });
            }
        }

        try{
            boolean isStop = threadPool.awaitTermination(5, TimeUnit.SECONDS);
            System.out.println("is pool is stop:" + isStop);
            System.out.println(Thread.currentThread().getName()+"\t1111111111111111111");
        } catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("-------------------------");
        System.out.println(Thread.currentThread().getName()+"\t all tests is over");
        System.out.println();
    }

    private static void shutdown_awaitTermination_Test() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //提交10个任务，在第5个任务提交完，准备提交第6个的时候执行shutdown
        for (int i = 1; i <= 10; i++) {
            System.out.println("第:" + i + " 次提交:threadPool.isShutdown: " + threadPool.isShutdown());
            //此处故意不加try...catch块，方便效果演示
            try {
                threadPool.execute(new Task(i));
            } catch (RejectedExecutionException e) {
                System.out.println("rejected,task-" + i);
            }
            //i等于5的时候shutdown，意味着从第6次开始就不能提交新任务
            if (i == 5) {
                threadPool.shutdown();
                System.out.println("i等于5的时候shutdown, 意味着从第六次开始不能提交新任务");
                System.out.println();
            }
        }
        try{
            /**
             * 任务没执行完且没到设定时间，是不会执行最下面两行打印代码的。
             *
             * 现在把等待时间设置为4秒，达到设置时间后，就不再阻塞当前线程了，
             * 直接打印了下面两行代码，并且返回了 false 说明线程池没有停止。
             *
             * 有时我们需要主线程等所有子线程执行完毕后再运行，在所有任务提交后，
             * 调用shutdown触发 awaitTermination，阻塞主线程，当所有子线程执行完毕后，解除阻塞。
             */
            boolean isStop = threadPool.awaitTermination(5, TimeUnit.SECONDS);
            System.out.println("is pool is stop:" + isStop);
            System.out.println(Thread.currentThread().getName()+"\t1111111111111111111");
        } catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("-------------------------");
        System.out.println(Thread.currentThread().getName()+"\t mission is over");
        System.out.println();
    }

    private static void shutdownNow_Test() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //提交10个任务，在第5个任务提交完，准备提交第6个的时候执行shutdown
        for (int i = 1; i <= 10; i++) {
            System.out.println("第:" + i + " 次提交:threadPool.isShutdown: " + threadPool.isShutdown());
            //此处故意不加try...catch块，方便效果演示
            try {
                threadPool.execute(new Task(i));
            } catch (RejectedExecutionException e) {
                System.out.println("rejected,task-" + i);
            }
            //i等于5的时候shutdown，意味着从第6次开始就不能提交新任务
            if (i == 5) {
                List<Runnable> runnables = threadPool.shutdownNow();// 关闭后不是线程池立即停止,等待前面已经提交的任务结束,不在接收新的任务
                runnables.forEach((runnable) -> {
                    if (runnable instanceof Task) {
                        System.out.println("waiting task: " + ((Task) runnable).getName());
                    }
                });
            }
        }
    }

    /**
     * 第6个任务开始及之后的任务都被拒绝了，1~5号任务正常执行。
     * 所以 shutdown 方法将线程池状态置为 SHUTDOWN，线程池并不会立即停止，
     * 要等正在执行和队列里等待的任务执行完才会停止。
     */
    private static void shutdown_Test() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //提交10个任务，在第5个任务提交完，准备提交第6个的时候执行shutdown
        for (int i = 1; i <= 10; i++) {
            System.out.println("第:" + i + " 次提交:threadPool.isShutdown: " + threadPool.isShutdown());
            //此处故意不加try...catch块，方便效果演示
            threadPool.execute(new Task(i));
            /*try {
                threadPool.execute(new Task(i));
            } catch (RejectedExecutionException e) {
                e.printStackTrace();
            }*/
            //i等于5的时候shutdown，意味着从第6次开始就不能提交新任务
            if (i == 5) {
                threadPool.shutdown();// 关闭后不是线程池立即停止,等待前面已经提交的任务结束,不在接收新的任务
            }
        }
        System.out.println(Thread.currentThread().getName()+"\t1111111111111111111");// 这里只要把异常捕捉,也能执行到
    }

    /**
     * 线程执行的任务
     * 在内部类中写 storage
     */
    static class Task implements Runnable {
        @Getter
        String name = "";

        public Task(Integer i) {
            name = "task-" + i;
        }

        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println("sleep completed, " + getName());
            } catch (InterruptedException e) {
                //当线程正在等待、休眠或被占用，并且线程在 Activity 之前或期间中断时引发。有时，方法可能希望测试当前线程是否已中断，如果是，则立即引发此异常。
                e.printStackTrace();
                System.out.println("interrupted, " + getName());
            } finally {

            }
            System.out.println(getName() + " finished");
            System.out.println();
        }
    }

    /**
     * 参考官网使用，最后的终结，优雅关停，but有点费事
     * @param threadPool
     */
    public static void finalOK_shutdownAndAwaitTermination(ExecutorService threadPool) {
        if (threadPool!=null && !threadPool.isShutdown()) {
            threadPool.shutdown();
            try {
                if (!threadPool.awaitTermination(120,TimeUnit.SECONDS)){
                    threadPool.shutdownNow();
                    if (!threadPool.awaitTermination(120,TimeUnit.SECONDS)){
                        System.out.println("threadPool did not terminate");
                    }
                }
            } catch (InterruptedException e) {
                threadPool.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}



